package no.group.gowther.service;

import no.group.gowther.enums.FileType;
import no.group.gowther.enums.OnePieceType;
import no.group.gowther.exception.CannotResolveSuchImageTypeException;
import no.group.gowther.service.dto.*;
import no.group.gowther.service.dto.param.*;
import no.group.gowther.util.ImageUtils;
import no.group.gowther.util.PageUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class FilingServiceImpl implements FilingService {
    private static final Logger LOGGER = LoggerFactory.getLogger(FilingServiceImpl.class);

    @Autowired
    private FileManageService fileManageService;

    @Autowired
    private OnePieceService onePieceService;

    @Autowired
    private ImageService imageService;

    @Override
    public FilingDetailDTO getFilingDetail(FilingDetailQueryDTO queryDTO) {
        FilingDetailDTOCreator detailDTOCreator = null;
        if (queryDTO instanceof FileFilingDetailQueryDTO filingDetailQueryDTO) {
            detailDTOCreator = new FileFilingDetailDTOCreator(filingDetailQueryDTO);
        } else if (queryDTO instanceof OnePieceFilingDetailQueryDTO filingDetailQueryDTO) {
            detailDTOCreator = new OnePieceFilingDetailDTOCreator(filingDetailQueryDTO);
        }
        return detailDTOCreator != null ? detailDTOCreator.create() : null;
    }

    abstract static class FilingDetailDTOCreator {
        protected FilingDetailQueryDTO queryDTO;
        protected long total;

        public FilingDetailDTOCreator(FilingDetailQueryDTO queryDTO) {
            this.queryDTO = queryDTO;
        }

        public FilingDetailDTO create() {
            FilingDetailDTO filingDetailDTO = getEmptyInstance();
            filingDetailDTO.setDir(getIsDir());
            filingDetailDTO.setHasNext(getHasNext());
            filingDetailDTO.setImageCodes(getImageCodes());
            filingDetailDTO.setDimension(resolveDimension(getImagePath()));
//            filingDetailDTO.setSessionId(""); // 可能需要的优化，sessionId
            after(filingDetailDTO);
            return filingDetailDTO;
        }

        private ImageUtils.Dimension resolveDimension(Path imagePath) {
            ImageUtils.Dimension dimension = ImageUtils.Dimension.ZERO;
            try {
                if (imagePath != null) {
                    dimension = ImageUtils.getImageDimension(imagePath);
                }
            } catch (IOException | CannotResolveSuchImageTypeException e) {
                LOGGER.error("解析图像[{}]分辨率失败", imagePath);
            }
            return dimension;
        }

        protected abstract FilingDetailDTO getEmptyInstance();

        protected abstract boolean getIsDir();

        protected boolean getHasNext() {
            return !PageUtils.isLast(queryDTO.getPageNum(), queryDTO.getPageSize(), queryDTO.getIndex(), total);
        };

        protected abstract List<ImageCode> getImageCodes();

        protected abstract Path getImagePath();

        protected abstract void after(FilingDetailDTO filingDetailDTO);
    }

    class FileFilingDetailDTOCreator extends FilingDetailDTOCreator {
        private FileDTO fileDTO;
        private Path imagePath;

        public FileFilingDetailDTOCreator(FileFilingDetailQueryDTO queryDTO) {
            super(queryDTO);
        }

        @Override
        protected FilingDetailDTO getEmptyInstance() {
            FileFilingDetailQueryDTO query = (FileFilingDetailQueryDTO) queryDTO;
            ListDTO<FileDTO> fileDTOListDTO = fileManageService.listFile(new FileQueryListDTO(Paths.get(query.getDirPath()), query.getFileType(), query));
            this.total = fileDTOListDTO.total();
            this.fileDTO = fileDTOListDTO.list().get(this.queryDTO.getIndex());

            return new FileFilingDetailDTO();
        }

        @Override
        protected boolean getIsDir() {
            return fileDTO.getType() == FileType.DIR;
        }

        @Override
        protected List<ImageCode> getImageCodes() {
            if (fileDTO.getType() == FileType.IMAGE) {
                imagePath = fileDTO.getFile();
                return Collections.singletonList(fileDTO.getImageCode());
            } else if (fileDTO.getType() == FileType.DIR) {
                List<ImageCode> imageCodes = imageService.generateDirImageCode(fileDTO.getFile());
                if (!imageCodes.isEmpty()) {
                    imagePath = imageService.decodeImageCode(imageCodes.get(0).getImageCode());
                }
                return imageCodes;
            }
            return Collections.emptyList();
        }

        @Override
        protected Path getImagePath() {
            return imagePath;
        }

        @Override
        protected void after(FilingDetailDTO filingDetailDTO) {
            if (filingDetailDTO instanceof FileFilingDetailDTO fileFilingDetailDTO)
                fileFilingDetailDTO.setFilePath(fileDTO.getFile().toString());
        }
    }

    class OnePieceFilingDetailDTOCreator extends FilingDetailDTOCreator {
        private OnePieceDTO onePieceDTO;

        public OnePieceFilingDetailDTOCreator(FilingDetailQueryDTO queryDTO) {
            super(queryDTO);
        }

        @Override
        protected FilingDetailDTO getEmptyInstance() {
            OnePieceFilingDetailQueryDTO query = (OnePieceFilingDetailQueryDTO) queryDTO;
            OnePieceQueryDTO onePieceQueryDTO = new OnePieceQueryDTO(query);
            final List<OnePieceType> onePieceTypes = query.getType().stream().map(OnePieceType::valueOf).collect(Collectors.toList());
            onePieceQueryDTO.setType(onePieceTypes);
            onePieceQueryDTO.setTagId(query.getTagId());

            ListDTO<OnePieceListDTO> onePieceListDTO = onePieceService.queryList(onePieceQueryDTO);
            OnePieceListDTO dto = onePieceListDTO.list().get(query.getIndex());
            onePieceDTO = onePieceService.queryDetail(dto.getId());
            total = onePieceListDTO.total();
            return new OnePieceFilingDetailDTO();
        }

        @Override
        protected boolean getIsDir() {
            return onePieceDTO.getType() == OnePieceType.ALBUM;
        }

        @Override
        protected List<ImageCode> getImageCodes() {
            return onePieceDTO.getImageCodes();
        }

        @Override
        protected Path getImagePath() {
            return imageService.decodeImageCode(onePieceDTO.getImageCodes().get(0).getImageCode());
        }

        @Override
        protected void after(FilingDetailDTO filingDetailDTO) {
            if (filingDetailDTO instanceof OnePieceFilingDetailDTO onePieceFilingDetailDTO) {
                onePieceFilingDetailDTO.setOnePieceId(onePieceDTO.getId());
                onePieceFilingDetailDTO.setName(onePieceDTO.getName());
                onePieceFilingDetailDTO.setTag(onePieceDTO.getTag());
            }
        }
    }
}
